package com.gitee.zeric.codec.generaters;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.gitee.zeric.codec.exception.ParamErrorException;
import lombok.AllArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * 流水生成
 *
 * @author zj
 * @date 2021/12/18
 */
@AllArgsConstructor
public class WaterGenerater extends AbstractCodeGerator {

    private final StringRedisTemplate stringRedisTemplate;


    @Override
    public String generate(String ruleCode, JSONObject jsonObject) {
        RuleParam param = trans(RuleParam.class, jsonObject);
        Long min = param.getMin();
        Long max = param.getMax();
        Integer size = param.getSize();
        Integer step = param.getStep();
        String fill = StrUtil.isBlank(param.getFill())?"":param.getFill();
        //创建默认的脚本对象
        DefaultRedisScript<Long> script = new DefaultRedisScript<>();
        //设置默认的脚本数据源
        script.setScriptText(
                "if redis.call(\"EXISTS\",KEYS[1]) == 1 then\n" +
                        "     return redis.call(\"INCRBY\",KEYS[1],ARGV[1])\n" +
                        "   else\n" +
                        "     return redis.call(\"INCRBY\",KEYS[1],ARGV[2])\n" +
                        "   end"
        );
        //设置返回值的类型
        script.setResultType(Long.class);
        List<String> keys = new ArrayList<>();
        keys.add(CodeGenerater.REDIS_DB_INCRMENT_CODE_RULE_PREFIX + ruleCode);
        Long execute = stringRedisTemplate.execute(script, keys, step.toString(), String.valueOf(min + step));
        if (execute == null) {
            return "-1";
        }
        execute = execute <= max ? execute : max;
        if (StrUtil.isNotBlank(fill)) {
            return String.format("%" + size + "d", execute).replace(" ", fill);
        }
        return execute.toString();
    }

    @Override
    protected String[] fields() {
        return new String[]{"min", "step", "max", "size"};
    }

    @Override
    public void checkParam(JSONObject paramJson) {
        super.checkParam(paramJson);
        RuleParam param = trans(RuleParam.class, paramJson);
        Long min = param.getMin();
        Long max = param.getMax();
        Integer step = param.getStep();
        if (min > Integer.MAX_VALUE - 1 || min < 0) {
            throw new ParamErrorException("编码规则min范围有误！min=" + min);
        }
        if (max > Integer.MAX_VALUE - 1 || max < 0) {
            throw new ParamErrorException("编码规则max范围有误！max=" + max);
        }
        if (min > max) {
            throw new ParamErrorException("最小值不能大于最大值！");
        }
        if (step < 1 || step > 1000) {
            throw new ParamErrorException("步长只能位于1到1000");
        }


    }

}
